package app

import "math"

// Source 水源划分
type Source struct {

	//========模型参数========//
	SM float64 `json:"SM"` //表层自由水蓄水容量/mm ，敏感
	EX float64 `json:"EX"` //表层自由水蓄水容量方次，不敏感，1.0~1.5
	KG float64 `json:"KG"` //表层自由水蓄水库对地下水的日出流系数，敏感
	KI float64 `json:"KI"` //表层自由水蓄水库对壤中流的日出流系数，敏感
	//========模型状态========//
	R float64 `json:"R"`
	//double R;	 //总径流量，mm
	RS float64 `json:"RS"`
	//double RS;   //地面径流，mm
	RI float64 `json:"RI"`
	//double RI;   //壤中流，mm
	RG float64 `json:"RG"`
	//double RG;   //地下径流，mm
	PE float64 `json:"PE"`
	//double PE;	 //净雨量，mm
	FR float64 `json:"FR"`
	//double FR;	 //本时段产流面积比例
	S0 float64 `json:"S0"`
	//double S0;   //本时段初的自由水蓄量，mm
	S float64 `json:"S"`
	//double S;    //本时段的自由水蓄量，mm

	M float64 `json:"M"`
	//double M;    //一天划分的计算时段数
	KID float64 `json:"KID"`
	//double KID;   //表层自由水蓄水库对壤中流的计算时段出流系数，敏感
	KGD float64 `json:"KGD"`
	//double KGD;    //表层自由水蓄水库对地下水的计算时段出流系数，敏感
	SMM float64 `json:"SMM"`
	//double SMM;    //全流域单点最大的自由水蓄水容量，mm
	SMMF float64 `json:"SMMF"`
	//double SMMF;  //产流面积上最大一点的自由水蓄水容量，mm
	SMF float64 `json:"SMF"`
	//double SMF;   //产流面积上的平均自由水蓄水容量深，mm
	AU float64 `json:"AU"`
	//double AU;   //相应平均蓄水深的最大蓄水深，S0值对应的纵坐标，mm
	RSD float64 `json:"RSD"`
	//double RSD;  //计算步长地面径流，mm
	RID float64 `json:"RID"`
	//double RID;  //计算步长壤中流，mm
	RGD float64 `json:"RGD"`
	//double RGD;  //计算步长地下径流，mm
	FR0 float64 `json:"FR0"`
	//double FR0;   //上一时段产流面积比例
	N int `json:"N"`
	//int N;       //N 为计算时段分段数，每一段为计算步长
	Q float64 `json:"Q"`
	//double Q;     //Q 是每个计算步长内的净雨量，mm
	KIDD float64 `json:"KIDD"`
	//double KIDD;   //表层自由水蓄水库对壤中流的计算步长出流系数，敏感
	KGDD float64 `json:"KGDD"`
	//double KGDD;   //表层自由水蓄水库对地下水的计算步长出流系数，敏感
	DT float64 `json:"DT"`
	//double dt;   //模型计算时段长,h
}

func (e *Source) SetParams(para *Params) {
	// 默认参数
	e.N = 1
	e.S0 = 0

	e.SM = para.MSM
	e.EX = para.MEX
	e.KI = para.MKI
	e.KG = para.MKG
}

func (e *Source) SetState(s *State) {
	e.R = s.R
	e.PE = s.PE
	e.FR = s.FR
	e.S0 = s.S0
	e.DT = s.DT
}

func (e *Source) Calculate() {

	// 计算时间步长，每日的时间步长，dt为时间间隔
	e.M = 24.0 / e.DT

	KIpKG := e.KI + e.KG
	KIdKG := e.KI / e.KG

	KID := (1 - math.Pow(1-(KIpKG), 1.0/e.M)) / (1 + KIdKG) // 计算KID，用于描述渗透和地下水流的关系 也就是KSSD

	KGD := KID * e.KG / e.KI // 计算KGD，用于描述地下水流和渗透的关系，也就是RGD

	// 先判断净雨量是否很小，如果是这简单计算
	if e.PE <= 1e-5 {
		e.RS = 0
		e.RI = KID * e.S0 * e.FR
		e.RG = KGD * e.S0 * e.FR
		e.S = e.S0 * (1 - KID - KGD)
	} else {
		// 修正过的最大储水量
		e.SMM = e.SM * (1 + e.EX)

		// 保存上一阶段的渗透比例
		e.FR0 = e.FR

		// 重新计算渗透比例
		e.FR = e.R / e.PE

		if e.FR > 1 {
			e.FR = 1
		}
		// 根据渗透比率调整储水量
		e.S = e.S0 * e.FR0 / e.FR

		// 采用5mm 净雨量 拆分计算 减小误差
		e.N = int(e.PE/5) + 1

		// 计算每段的降水量Q
		e.Q = e.PE / float64(e.N)

		e.KIDD = (1 - math.Pow(1-(KID+KGD), float64(1.0/e.N))) / (1 + KGD/KID) // 计算KIDD，表示每段之间的渗透和地下水流关系

		e.KGDD = e.KIDD * KGD / KID // 计算KGDD，地下水流的修正系数
		e.RS = 0.0                  // 初始化表面径流
		e.RI = 0.0                  // 初始化渗透水量
		e.RG = 0.0                  // 初始化地下水流量

		// EX 越小，代表分布越均匀，产流平稳
		if e.EX == 0 {
			e.SMMF = e.SMM
		} else {
			// 根据FR和EX调整SMMF
			e.SMMF = (1 - math.Pow(1-e.FR, 1.0/e.EX)) * e.SMM
		}

		e.SMF = e.SMMF / (1 + e.EX)

		for i := 0; i < e.N; i++ {
			if e.S > e.SMF {
				e.S = e.SMF
			}
			// 修正自由水
			e.AU = e.SMMF * (1 - math.Pow((1-e.S/e.SMF), 1/(1+e.EX)))

			if e.Q+e.AU >= e.SMMF {
				e.RSD = (e.Q + e.S - e.SMF) * e.FR
				e.RID = e.SMF * e.KIDD * e.FR
				e.RGD = e.SMF * e.KGDD * e.FR
				e.S = e.SMF - (e.RID+e.RGD)/e.FR
			} else {
				e.RSD = (e.S + e.Q - e.SMF + e.SMF*math.Pow(1-(e.Q+e.AU)/e.SMMF, 1+e.EX)) * e.FR // 计算表面径流RSD
				e.RID = (e.S*e.FR + e.Q*e.FR - e.RSD) * e.KIDD                                   // 计算渗透水量RID
				e.RGD = (e.S*e.FR + e.Q*e.FR - e.RSD) * e.KGDD                                   // 计算地下水流量RGD
				e.S = e.S + e.Q - (e.RSD+e.RID+e.RGD)/e.FR                                       // 更新储水量S
			}

			e.RS = e.RS + e.RSD
			e.RI = e.RI + e.RID
			e.RG = e.RG + e.RGD

		}

	}
}

func (e *Source) UpdateState(s *State) {
	s.RS = e.RS
	s.RI = e.RI
	s.RG = e.RG
	s.S0 = e.S
	s.FR = e.FR
}
